/**
 * Fucked by LPJ on 2018/1/24.
 */
import java.text.DecimalFormat
import org.junit.Test
import kotlin.test.assertEquals

fun doubles(maxk: Int, maxn: Int): Double {
    var result = 0.0
    for (k in 1..maxk) {
        var some = 1 / Math.pow(2.0, 2.0 * k)
        var temp = some
        for (n in 2..maxn) {
            temp *= Math.pow(n / (n + 1.0), 2.0 * k)
            some += temp
        }
        result += some / k
    }
    return result
}

class DoublesMainTest {
    private fun randInt(min:Int, max:Int):Int {
        return min + (Math.random() * ((max - min) + 1)).toInt()
    }
    private fun assertFuzzyEquals(act:Double, exp:Double) {
        val inrange = Math.abs(act - exp) <= 1e-6
        if (inrange == false)
        {
            val df = DecimalFormat("#0.000000")
            println("At 1e-6: Expected must be " + df.format(exp) + ", but got " + df.format(act))
        }
        assertEquals(true, inrange)
    }
    @Test
    fun test1() {
        println("Fixed Tests: doubles")
        assertFuzzyEquals(doubles(1, 10), 0.5580321939764581) // 0.5580321939764581
        assertFuzzyEquals(doubles(10, 1000), 0.6921486500921933) // 0.6921486500921933
        assertFuzzyEquals(doubles(10, 10000), 0.6930471674194457) // 0.6930471674194457
        assertFuzzyEquals(doubles(20, 10000), 0.6930471955575918) // 0.6930471955575918
        assertFuzzyEquals(doubles(30, 10000), 0.693047195557606) // 0.693047195557606
        assertFuzzyEquals(doubles(90, 10000), 0.693047195557606) // 0.693047195557606
        assertFuzzyEquals(doubles(100, 10000), 0.693047195557606) // 0.693047195557606 0.59s
        assertFuzzyEquals(doubles(1000, 10000), 0.693047195557606) // 0.693047195557606
        assertFuzzyEquals(doubles(100, 100000), 0.6931371807099251)// 0.6931371807099251
        assertFuzzyEquals(doubles(10, 100), 0.6832948559787737) // 0.6832948559787737
        assertFuzzyEquals(doubles(25, 12000), 0.6930638576419238)// 0.6930638576419238
        assertFuzzyEquals(doubles(40, 15000), 0.6930805205592468)// 0.6930805205592468
    }
    private fun doublesSol(maxk:Int, maxn:Int):Double {
        var k = 1
        var sm = 0.0
        while (k <= maxk)
        {
            var n = 2
            var vk = 1 / (k * Math.pow(2.0, (2 * k).toDouble()))
            var uk = vk
            while (n <= maxn)
            {
                vk *= Math.pow(n / (n + 1).toDouble(), (2 * k).toDouble())
                uk += vk
                n++
            }
            sm += uk
            k++
        }
        return sm
    }
    @Test
    fun test4() {
        println("Random Tests")
        for (i in 0..9)
        {
            val k = randInt(1, 50)
            val n = randInt(1000, 25000)
            assertFuzzyEquals(doubles(k, n), doublesSol(k, n))
        }
    }
}